package com.bestv.search.engine.xfire;

import com.bestv.search.common.model.AccessLog;
import com.bestv.search.common.model.History;
import com.bestv.search.common.model.SearchKeywordWrapper;
import com.bestv.search.common.util.StringConst;
import com.bestv.search.engine.accesslog.AccessLogAnalyzer;
import com.bestv.search.engine.command.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.queryParser.ParseException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.util.*;

//$Id: LuceneSearchWS.java 124 2012-11-28 08:43:53Z luo.xiaojun $
public class LuceneSearchWS implements ISearchWS {

    protected final Log log = LogFactory.getLog(getClass());
    private LuceneSearchCommandForWS searchCommand;
    private HitCommand hit;
    private HistoryCommand history;
    private InfoCommand infoCommand;
    private TopNCacheCommand topNCacheCommand;

    public String searchPreview(String json) throws JSONException {
        JSONObject jo = new JSONObject(json);
        String keywords = jo.getString("keywords");
        String fields = jo.getString("fields");
        int start = -1;
        int limit = -1;
        try {
            start = jo.getInt("start");
            limit = jo.getInt("limit");
        } catch (Exception e) {
            log.error(e);
        }
        JSONArray array;
        log.debug("keywords: " + keywords);
        log.debug("fields: " + fields);
        log.debug("start: " + start);
        log.debug("limit: " + limit);
        array = jo.getJSONArray("filters");
        String types = "", p_types = "", updateTime = "";
        if (array == null)
            log.debug("null");
        else {
            log.debug("filters.length:　" + array.length());
            for (int i = 0; i < array.length(); ++i) {
                JSONObject ft = array.getJSONObject(i);
                log.debug("{'" + ft.getString("filterField") + "':'" + ft.getString("filterValue") + "'}");
                if ("p_type".equals(ft.getString("filterField"))) {
                    p_types = ft.getString("filterValue");
                } else if ("type".equals(ft.getString("filterField"))) {
                    types = ft.getString("filterValue");
                } else if ("updateTime".equals(ft.getString("filterField"))) {
                    updateTime = ft.getString("filterValue");
                }
            }
        }
        return searchCommand.searchPreview(keywords, fields, p_types, types, updateTime, start, limit);
    }

    public String searchInOneFieldAndPtypeByOneKeyword(String ptype, String field, String keyword, int start, int limit) {
        return searchCommand.searchInOneFieldAndPtypeByOneKeyword(ptype, field, keyword, start, limit);
    }

    public String searchInType(String ptype, String keywords, String must, int start, int limit) throws ParseException {
        return searchCommand.searchInType(ptype, keywords, must, start, limit, true);
    }

    public String searchOutType(String ptype, String keywords, String must, int start, int limit) throws ParseException {
        return searchCommand.searchInType(ptype, keywords, must, start, limit, false);
    }

    public String searchByDoc(byte[] xmlDoc, String cmd) {

        SAXReader reader = new SAXReader();
        Document doc;
        try {
            doc = reader.read(new ByteArrayInputStream(xmlDoc));
        } catch (DocumentException e) {
            log.error("Error!The Request Parameter cannot parse to XML");
            return null;
        }

        return LuceneSearchCommandRefactor.getSingletonLuceneSearchCommand().search(doc, cmd, StringConst.EMPTY);
    }

    public String getPersonByDoc(String personId, String avatarRoot, int productFlag) {
        return LuceneSearchCommandRefactor.getPersonDetailsById(personId, avatarRoot, productFlag);
    }

    public List<SearchKeywordWrapper> hitKeywordSync() {
        return hit.hitKeywordList();
    }

    public void clearEngineKeyword() {
        hit.clear();
    }

    public void hitLock() {
        hit.lockQueue();
    }

    public void hitFree() {
        hit.freeQueue();
    }

    public List<History> historySync() {
        List<History> result = new ArrayList<History>();
        Map<String, History> historyMap = history.getQueue().getFirstLevelMap();
        for (String userId : historyMap.keySet()) {
            result.add(historyMap.get(userId));
        }
        return result;
    }

    public void clearEngineHistory() {
        history.clear();
    }

    public void historyLock() {
        history.lockQueue();
    }

    public void historyFree() {
        history.freeQueue();
    }

    public LuceneSearchCommandForWS getSearchCommand() {
        return searchCommand;
    }

    public void setSearchCommand(LuceneSearchCommandForWS searchCommand) {
        this.searchCommand = searchCommand;
    }

    public HitCommand getHit() {
        return hit;
    }

    public void setHit(HitCommand hit) {
        this.hit = hit;
    }

    public HistoryCommand getHistory() {
        return history;
    }

    public void setHistory(HistoryCommand history) {
        this.history = history;
    }

    public List<AccessLog> accessLogSync(String siteCode, int serverNo, Date lastAnalyzeDate, int maxAnalyzeDays,
                                         String logsFolder) {
        List<AccessLog> syncResult = new ArrayList<AccessLog>();
        Hashtable<Date, List<AccessLog[]>> table = new AccessLogAnalyzer().getAccessLog(siteCode, serverNo,
                lastAnalyzeDate, maxAnalyzeDays, logsFolder);
        for (List<AccessLog[]> list : table.values()) {
            for (AccessLog[] logs : list) {
                for (AccessLog log : logs) {
                    if (log != null)
                        syncResult.add(log);
                }
            }
        }

        return syncResult;
    }

    public String getTopNINfosToJSON(String type, boolean increase, int mergeType, int limit, String[] categorys)
            throws JSONException {
        return infoCommand.topnJSONToMgmt(type, increase, mergeType, limit, categorys);
    }

    public List<List<String>> topnToList(String type, boolean increase, int mergeType, int limit, String[] categorys) {
        return infoCommand.topnToList(type, increase, mergeType, limit, categorys);
    }

    public void updateTopNCacheInMemory() {
        topNCacheCommand.updateMemoryCache();
    }

    public InfoCommand getInfoCommand() {
        return infoCommand;
    }

    public void setInfoCommand(InfoCommand infoCommand) {
        this.infoCommand = infoCommand;
    }

    public TopNCacheCommand getTopNCacheCommand() {
        return topNCacheCommand;
    }

    public void setTopNCacheCommand(TopNCacheCommand topNCacheCommand) {
        this.topNCacheCommand = topNCacheCommand;
    }
}
